package com.zyf.project.binaryproto.encoder.impl;

import com.zyf.project.binaryproto.converter.FixedValueConverter;
import com.zyf.project.binaryproto.specification.BinarySliceSpecification;
import com.zyf.project.binaryproto.specification.FieldSpecification;
import org.jetbrains.annotations.NotNull;
import utils.binary.BytesSlices;
import utils.binary.impl.BytesSlice;
import utils.binary.impl.FixedBytesSliceArray;
import utils.binary.io.BytesInputStream;
import utils.binary.io.BytesOutputBuffer;
import utils.io.NumberMask;

import java.lang.reflect.Array;
import java.lang.reflect.Method;

/**
 * <h1>静态数组编码器</h1>
 * <p>所谓静态就是数组长度固定</p>
 * <p>继承了 {@link AbstractFieldEncoder}</p>
 *
 * @author Zhou Yifan
 */
public class FixedArrayFieldEncoder extends AbstractFieldEncoder {

    protected FixedValueConverter valueConverter;

    public FixedArrayFieldEncoder(
            BinarySliceSpecification sliceSpecification,
            FieldSpecification fieldSpecification,
            @NotNull Method reader,
            FixedValueConverter valueConverter) {
        super(sliceSpecification, fieldSpecification, reader);
        this.valueConverter = valueConverter;
    }

    /**
     * 将数据序列化到指定缓存中
     *
     * @param dataContract 数据
     * @param buffer       指定缓存 {@link BytesOutputBuffer}
     * @return 写入的字节数
     */
    @Override
    public int encode(Object dataContract, BytesOutputBuffer buffer) {
        int size = 0;

        Object values = readValue(dataContract);
        size += encodeArray(values, buffer);

        return size;
    }

    /**
     * 对数组类型的值进行固定长度的编码；
     *
     * @param values 待编码对象
     * @param buffer 目标缓冲区
     * @return 写入的字节数
     */
    protected int encodeArray(Object values, BytesOutputBuffer buffer) {
        int count = values == null ? 0 : Array.getLength(values);

        int counterSize = NumberMask.NORMAL.getMaskLength(count);
        int elementSize = sliceSpecification.getLength();

        int size = counterSize + elementSize * count;
        byte[] outBuff = new byte[size];
        NumberMask.NORMAL.writeMask(count, outBuff, 0);

        for (int i = 0; i < count; i++) {
            valueConverter.encode(Array.get(values, i), outBuff, counterSize + elementSize * i);
        }

        buffer.write(outBuff);
        return size;
    }

    /**
     * 将 BytesInputStream 反序列化成数据片
     *
     * @param bytesInputStream {@link BytesInputStream}
     * @return {@link BytesSlices}
     */
    @Override
    public BytesSlices decode(BytesInputStream bytesInputStream) {
        return FixedBytesSliceArray.resolve(bytesInputStream, sliceSpecification.getLength());
    }

    /**
     * 字段解码
     *
     * @param fieldBytes 一组相关联的数据片段 {@link BytesSlices}
     * @return 对象 {@link Object}
     */
    @Override
    public Object decodeField(BytesSlices fieldBytes) {
        if (fieldBytes == null) {
            throw new IllegalArgumentException("FieldBytes is null!");
        }
        int fieldCount = fieldBytes.getCount();
        Object[] values;
        if (null != valueConverter.getArrayConstructor()) {
            values = (Object[]) valueConverter.getArrayConstructor().apply(fieldCount);
        } else {
            values = (Object[]) Array.newInstance(valueConverter.getValueType(), fieldCount);
        }
        BytesSlice itemSlice;
        for (int i = 0; i < values.length; i++) {
            itemSlice = fieldBytes.getDataSlice(i);
            if (itemSlice.getSize() == 0) {
                values[i] = valueConverter.getDefaultValue();
            } else {
                values[i] = valueConverter.decode(itemSlice);
            }
        }
        return values;
    }
}
